package com.jzo2o.health.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.common.constants.UserType;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.mapper.OrdersMapper;
import com.jzo2o.health.model.UserThreadLocal;
import com.jzo2o.health.model.domain.Orders;
import com.jzo2o.health.model.domain.OrdersCancelled;
import com.jzo2o.health.model.dto.OrderCountDTO;
import com.jzo2o.health.model.dto.request.OrdersPageQueryReqDTO;
import com.jzo2o.health.model.dto.response.AdminOrdersDetailResDTO;
import com.jzo2o.health.model.dto.response.OrdersCountResDTO;
import com.jzo2o.health.model.dto.response.OrdersDetailResDTO;
import com.jzo2o.health.model.dto.response.OrdersResDTO;
import com.jzo2o.health.service.IOrderCancelService;
import com.jzo2o.health.service.IOrderManagerService;
import com.jzo2o.health.service.IReservationSettingService;
import com.jzo2o.mysql.utils.PageUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 订单管理相关业务层实现
 * @author JIAN
 */
@Service
public class OrderManagerServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrderManagerService {
    @Resource
    private IOrderCancelService orderCancelService;
    @Resource
    private IReservationSettingService reservationSettingService;

    @Override
    public PageResult<OrdersResDTO> pageQuery(OrdersPageQueryReqDTO ordersPageQueryReqDTO) {
        Page<Orders> ordersPage = PageUtils.parsePageQuery(ordersPageQueryReqDTO, Orders.class);

        Integer orderStatus = ordersPageQueryReqDTO.getOrderStatus();
        String memberPhone = ordersPageQueryReqDTO.getMemberPhone();

        Page<Orders> page = lambdaQuery()
                .eq(ObjectUtils.isNotEmpty(orderStatus), Orders::getOrderStatus, orderStatus)
                .like(ObjectUtils.isNotEmpty(memberPhone), Orders::getMemberPhone, memberPhone)
                .page(ordersPage);

        return PageUtils.toPage(page, OrdersResDTO.class);
    }

    @Override
    public List<OrdersResDTO> pageQuery(Integer orderStatus, Long sortBy) {
        Long userId = UserThreadLocal.currentUserId();
        if (ObjectUtils.isEmpty(userId)) {
            throw new ForbiddenOperationException("无法获取当前用户");
        }

        // 默认每页10条数据
        List<Orders> ordersList = lambdaQuery()
                .eq(Orders::getMemberId, userId)
                .eq(ObjectUtils.isNotEmpty(orderStatus), Orders::getOrderStatus, orderStatus)
                .lt(ObjectUtils.isNotEmpty(sortBy), Orders::getSortBy, sortBy)
                .last("LIMIT 10")
                .list();

        if (CollUtils.isEmpty(ordersList)) {
            return new ArrayList<>();
        } else {
            return ordersList.stream()
                    .map(order -> BeanUtils.toBean(order, OrdersResDTO.class))
                    .collect(Collectors.toList());
        }
    }

    @Override
    public AdminOrdersDetailResDTO getAggregationInfo(Long id) {
        AdminOrdersDetailResDTO adminOrdersDetailResDTO = new AdminOrdersDetailResDTO();

        Orders orders = baseMapper.selectById(id);
        if (ObjectUtils.isEmpty(orders)) {
            return adminOrdersDetailResDTO;
        }

        // 订单信息
        adminOrdersDetailResDTO.setOrderInfo(
                BeanUtils.toBean(orders, AdminOrdersDetailResDTO.OrderInfo.class));

        // 支付信息
        AdminOrdersDetailResDTO.PayInfo payInfo = BeanUtils.toBean(orders, AdminOrdersDetailResDTO.PayInfo.class);
        payInfo.setThirdOrderId(orders.getTransactionId());
        adminOrdersDetailResDTO.setPayInfo(payInfo);

        OrderStatusEnum orderStatus = orders.getOrderStatus();
        if (OrderStatusEnum.CANCELLED == orderStatus) {
            OrdersCancelled cancelInfo = orderCancelService.getById(orders.getId());

            // 取消信息
            adminOrdersDetailResDTO.setCancelInfo(AdminOrdersDetailResDTO.CancelInfo.builder()
                    .cancelReason(cancelInfo.getCancelReason())
                    .cancelTime(cancelInfo.getCancelTime())
                    .build());

            // 退款信息
            adminOrdersDetailResDTO.setRefundInfo(AdminOrdersDetailResDTO.RefundInfo.builder()
                    .refundStatus(payInfo.getPayStatus())
                    .cancelTime(cancelInfo.getCancelTime())
                    .cancelReason(cancelInfo.getCancelReason())
                    .tradingChannel(orders.getTradingChannel())
                    .refundId(orders.getRefundId())
                    .build());

            payInfo.setPayStatus(OrderPayStatusEnum.PAY_SUCCESS.getStatus());
        } else if (OrderStatusEnum.CLOSED == orderStatus) {
            OrdersCancelled cancelInfo = orderCancelService.getById(orders.getId());

            // 取消信息
            adminOrdersDetailResDTO.setCancelInfo(AdminOrdersDetailResDTO.CancelInfo.builder()
                    .cancelReason(cancelInfo.getCancelReason())
                    .cancelTime(cancelInfo.getCancelTime())
                    .build());

            payInfo.setPayStatus(OrderPayStatusEnum.PAY_SUCCESS.getStatus());
        }

        return adminOrdersDetailResDTO;
    }

    @Override
    public OrdersDetailResDTO getOrderById(Long id) {
        Orders orders = baseMapper.selectById(id);
        if (ObjectUtils.isEmpty(orders)) {
            return new OrdersDetailResDTO();
        }
        OrdersDetailResDTO ordersDetailResDTO = BeanUtils.toBean(orders, OrdersDetailResDTO.class);

        // 订单超时则取消
        if (orders.getOrderStatus() == OrderStatusEnum.NO_PAY
                && orders.getPayStatus() == OrderPayStatusEnum.NO_PAY
                && orders.getCreateTime().isBefore(LocalDateTime.now().minusMinutes(15))) {
            orderCancelService.cancelOrder(OrdersCancelled.builder()
                    .id(id)
                    .cancelTime(LocalDateTime.now())
                    .cancelReason("订单超时自动取消")
                    .cancellerType(UserType.SYSTEM)
                    .build());

            // 已预约人数 - 1
            reservationSettingService.plusReservationCount(orders.getReservationDate(), -1);

            ordersDetailResDTO.setOrderStatus(OrderStatusEnum.CANCELLED);
        }

        if (orders.getOrderStatus() == OrderStatusEnum.CANCELLED
                || orders.getOrderStatus() == OrderStatusEnum.CLOSED) {
            OrdersCancelled cancelInfo = orderCancelService.getById(id);

            ordersDetailResDTO.setCancelReason(cancelInfo.getCancelReason());
            ordersDetailResDTO.setCancelTime(cancelInfo.getCancelTime());
        }

        return ordersDetailResDTO;
    }

    @Override
    public OrdersCountResDTO countByStatus() {
        OrdersCountResDTO ordersCountResDTO = new OrdersCountResDTO();

        List<OrderCountDTO> orderCountList = baseMapper.countStatus();
        if (CollUtils.isEmpty(orderCountList)) {
            return ordersCountResDTO;
        }

        Map<Integer, Integer> map = orderCountList
                .stream()
                .collect(Collectors
                        .toMap(OrderCountDTO::getOrderStatus, OrderCountDTO::getCount));

        Integer noPayCount = map.getOrDefault(OrderStatusEnum.NO_PAY.getStatus(), 0);
        Integer waitingCheckupCount = map.getOrDefault(OrderStatusEnum.WAITING_CHECKUP.getStatus(), 0);
        Integer completedCheckupCount = map.getOrDefault(OrderStatusEnum.COMPLETED_CHECKUP.getStatus(), 0);
        Integer closedCount = map.getOrDefault(OrderStatusEnum.CLOSED.getStatus(), 0);
        Integer cancelledCount = map.getOrDefault(OrderStatusEnum.CANCELLED.getStatus(), 0);

        ordersCountResDTO.setNoPayCount(noPayCount);
        ordersCountResDTO.setWaitingCheckupCount(waitingCheckupCount);
        ordersCountResDTO.setCompletedCheckupCount(completedCheckupCount);
        ordersCountResDTO.setClosedCount(closedCount);
        ordersCountResDTO.setCancelledCount(cancelledCount);
        ordersCountResDTO.setTotalCount(noPayCount + waitingCheckupCount + completedCheckupCount + closedCount + cancelledCount);

        return ordersCountResDTO;
    }
}